<?php

// Namespace

namespace Loop;


/**
 * CSharedObject is a class that can be used to sharedObject
 */

class CSharedObject extends \Loop\CObject
{
	/**
	 * Easy way to create a shared object
	 * 
	 * @param	string	$objectExtensionId	The ID of the extension to which the object belongs
	 * @param	string	$objectClassName	The class of the object
	 * @param	int		$objectId			The ID of the object
	 * @param	string	$targetUri			The target URI
	 */
	
	public function create($objectExtensionId, $objectClassName, $objectId, $targetUri)
	{
		// Has the object already been shared by the user?

		$rawSharedObjects = $this->find
		(
			array
			(
				'conditions' => array
				(
					'objectClassName' => array(EQUAL, $objectClassName),
					'objectExtensionId' => array(EQUAL, $objectExtensionId),
					'objectId' => array(EQUAL, $objectId),
					'targetUri' => array(EQUAL, $targetUri),
					'userCreatorId' => array(EQUAL, user()->getId())
				)
			)
		);

		// If so, use the first occurence
		// Otherwise create a new shared object

		if (count($rawSharedObjects) > 0)
		{
			$rawSharedObject = array_pop($rawSharedObjects);
			$this->loadFromRawObject($rawSharedObject);
		}
		else
		{
			$stringHelper = app()->getStringHelper();


			// Set all required properties

			$this->setDurationOfAvailability(pref('[Loop]/model/CSharedObject/durationOfAvaibility'));
			$this->setObjectClassName($objectClassName);
			$this->setObjectExtensionId($objectExtensionId);
			$this->setObjectId($objectId);
			$this->setTargetUri($targetUri);


			// If universe is needed, encrypt it with token for private key

			$universe = pref('[Loop]/application/universe');

			if (empty($universe) === false)
			{
				// Create private key (token)

				$privateKey = $stringHelper->generateUniqueKey();


				// Encrypt universe

				$encryptedUniverse = $stringHelper->encrypt($universe, true, $privateKey);


				// Concat universe encrypted and private key

				$token = $encryptedUniverse . $privateKey;				

			}
			else
			{
				$token = $stringHelper->generateUniqueKey();				
			}


			$this->setToken($token);


			// Save the shared object

			$this->save();
		}
	}
	
	
	/**
	 *
	 */
	
	protected function createProperties()
	{
		$this->createProperty
		(
			'durationOfAvailability',
			array
			(
				'type' => TYPE_REAL
			)
		);
		
		$this->createProperty
		(
			'objectClassName',
			array
			(
				'type' => TYPE_STRING_MEDIUM
			)
		);

		$this->createProperty
		(
			'objectExtensionId',
			array
			(
				'type' => TYPE_STRING_MEDIUM
			)
		);
		
		$this->createProperty
		(
			'objectId',
			array
			(
				'type' => TYPE_ID
			)
		);
		
		$this->createProperty
		(
			'timeOfLastAccess',
			array
			(
				'type' => TYPE_TIMESTAMP
			)
		);
		
		$this->createProperty
		(
			'token',
			array
			(
				'isUnique' => true,
				'type' => TYPE_STRING_LONG
			)
		);
		
		$this->createProperty
		(
			'targetUri',
			array
			(
				'type' => TYPE_STRING_MEDIUM
			)
		);
	
	}
	
	
	/**
	 * Checks whether the shared object hasn't expired yet
	 *
	 * @return	bool	True if available, false otherwise
	 */
	
	protected function isAvailable()
	{
		// Use the last time the object was accessed if any

		$time = $this->getTimeOfLastAccess();
		
		if ($time == null)
		{
			// Otherwise use the time of creation

			$time = $this->getTimeOfCreation();
		}
		

		// So, is the object still available?

		if ((time() - $time) <= $this->getDurationOfAvailability())
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	
	/**
	 * Gets the URL of the shared object
	 *
	 * @return	string	The URL to the shared object
	 */
	
	public function getPublicUrl()
	{
		return url('shared/?t=' . urlencode($this->getToken()));
	}
	
	
	/**
	 * Loads a shared object from its token
	 * 
	 * @param	string	$token				The token associated with the shared object
	 * @param	bool	$checkAvailability	True to ensure the object is available, false to ignore
	 */
	
	public function loadFromToken($token, $checkAvailability = true)
	{
		$encryptedUniverse = substr($token, 0, -32);

		// If token is too long, there is maybe a universe

		if (strlen($encryptedUniverse) > 0)
		{
			// Decrypt universe

			$privateKey = substr($token, strlen($encryptedUniverse));
			$universe = app()->getStringHelper()->decrypt($encryptedUniverse, $privateKey);
			
			pref('[Loop]/application/universe', $universe, true);


			$this->databaseName = pref('[' . EXTENSION_APPLICATION . ']/database/name');			
		}


		// Look for shared objects with this token
		
		$rawSharedObjects = parent::find
		(
			array
			(
				'conditions' => array
				(
					'token' => array(EQUAL, $token)
				)
			)	
		);
		
		
		// Ensure that there is only one shared object

		$nbRawSharedObjects = count($rawSharedObjects);

		if ($nbRawSharedObjects == 0)
		{
			e
			(
				EXCEPTION_SHARED_OBJECT_NOT_FOUND,
				array
				(
					'token' => $token
				)
			);
		}
		else if ($nbRawSharedObjects > 1)
		{
			e
			(
				EXCEPTION_SHARED_OBJECT_TOO_MANY_FOUND,
				array
				(
					'nbRawSharedObjects' => $nbRawSharedObjects,
					'token' => $token
				)
			);
		}


		// Load the shared object
		
		$rawSharedObject = array_pop($rawSharedObjects);

		$this->loadFromRawObject($rawSharedObject);
		

		// Is the object is still available?

		if
		(
			($checkAvailability == true) &&
			($this->isAvailable() == false)
		)
		{
			e
			(
				EXCEPTION_SHARED_OBJECT_NOT_AVAILABLE,
				array
				(
					'token' => $token
				)
			);
		}
	}
}

?>
